#!/usr/bin/python
#coding:utf-8
'''
mos 
决策树回归
交叉验证：https://blog.csdn.net/xiaodongxiexie/article/details/71915259
'''

import numpy as np
from sklearn import tree 
from sklearn import model_selection
import matplotlib.pyplot as plt
import pandas
import time

import imp 
tool=imp.load_source('tool','./tool/tool.py')
import tool as tl

import sys

def load_data(url):
    dataframe = pandas.read_csv(url,header=0) #sep=",",skiprows=0,header=0
    #2757
    # print dataframe.shape
    # dataframe.fillna(0)
    #查看数据特征
    print dataframe.shape
    # print dataframe.describe()
    # print dataframe.ix[1,:]   #获取某一行所有列数据
    # print dataframe.ix[[1,3,2],:]   #获取某几行所有列数据

    #获取特征名
    # names= dataframe.columns
    # names = np.array(names,dtype=np.str) 
    # # print names.shape
    # names =names[0:names.shape[0]-1]
    # print names
    
    array = dataframe.values
    # x=np.delete(x,[21,24],axis=1)  #1 删除某几列  0 删除某几行
    # print array.shape

    x = array[:,3:array.shape[1]-1]   #特征
    y = array[:,array.shape[1]-1]  #标签 
    return x,y

def try_method(x,y):
    x_train,x_test,y_train,y_test = model_selection.train_test_split(x,y,test_size=0.3)  #30%用于验证
    '''
    criterion（mse）:
        测量分裂质量：MSE和MAE

    splitter:
        每个节点分类决策器选择，默认best（默认），选择最好的分类，random，选择最好的随机分类

    max_depth:
        树最大深度，当树深度到达max_depth时，无论还有可以分支的特征，决策树都会停止计算，默认None时，节点会一直扩展直到所有叶子都是纯的或者所有叶子节点都包含少于min_samples_split个样本点，忽视max_leaf_nodes是不是None

    min_samples_split:
        区分内部节点需要的最小的样本数，默认为2
        1、如果是int，将其作为最小的样本数
        2、如果为float，min_samples_split是一个百分率并且ceil（min_samples_split*n_samples）是每个分类需要的样本数。ceil是取大于或等于指定表达式的最小整数。

    min_samples_leaf:
        一个分支需要的最少样本数，默认为1
        1、如果是int，其为最小样本数
        2、如果为float，则它是一个百分率并且ceil（min_samples_leaf*n_samples）是每个节点所需要的样本数

    min_weight_fraction_leaf:
        一个叶节点的输入样本所需要的最小的加权分数。默认0

    max_features:
        分类时需要考虑的特征数，
        1、如果为int，每次分类需要考虑max_features个特征
        2、如果float，则max_features是一个百分率并且分类时需要考虑的特征数是int（max_features*n_features,其中n_features是训练完成时发特征数）
        3、如果是auto，max_features=auto(n_features)
        4、如果是sqrt，max_features=sqrt(n_features)
        5、如果是log2，max_features=log2(n_features)
        6、如果是None，max_features=n_features
        注意：至少找到一个样本点有效的被分类时，搜索分类才会停止

    random_state:
        可选int、RandomState instance、None。
        int：随机数字发生器的种子
        RandomState：random_state随机数字发生器
        None：随机数字发生器是np.random使用的RandomState instance

    max_leaf_nodes:
        最大叶节点数，None时无限制，取整数时，忽略max_depth

    min_impurity_decrease:
        默认0，节点划分最小不纯度，此值限制决策树的增长，如果某节点的不纯度（基尼系数，信息增益，均方差，绝对差）小于这个阀值，则该节点不可再生成子节点

    (弃用)min_impurity_split:
        分裂的不纯度阀值，当前节点不纯度小于此阀值时不分类

    presort:
        默认false，是否欲分类数据以加速训练时最好分类的查找。在有大数据集的决策树中，如果设置true可能会减慢训练的过程。当使用一个小数据集或一个深度受限的决策树中，可以减速训练的过程
    
    优化决策树影响比较大的：
        max_depth 限制决策树大小，和过拟合
        min_samples_leaf 避免决策树过拟合
        min_impurity_decrease 限制分裂，避免过拟合
    ''' 
    model=tree.DecisionTreeRegressor()

    # from  sklearn.linear_model import LinearRegression
    # model =LinearRegression()

    model.fit(x_train,y_train)
   
    # createPic(model)
    score = model.score(x_test,y_test)
    # print score
    #方差
    result = model.predict(x_test)
    # tl.say('预测值'+str(result))
    # tl.say('真实值'+str(y_test))
    #1、查准率 精确率 2、查全率 召回率
    

    # from sklearn.metrics import mean_absolute_error 
    # test = mean_absolute_error(y_test,result)
    # #期望值与真实值平均相差多大
    # tl.say("平均绝对误差（MAE）"+str(test))

    from sklearn.metrics import mean_squared_error
    test = mean_squared_error(y_test,result)
    #估计值与真实值之差平方的期望值，越小越好，纪为MSE，开根即为RMSE，均方根误差
    # tl.say("平均方差（MSE）"+str(test))
    return test

    #方程对预测值的拟合程度
    # from sklearn.metrics import r2_score
    # test=r2_score(y_test,result) #multioutput="uniform_average" variance_weighted,uniform_average,raw_values
    # tl.say("R平方值："+str(test))

    # from sklearn.model_selection import cross_val_score
    # test=cross_val_score(model,x,y,cv=2)
    # tl.say("交叉验证"+str(test))

    # plt.figure(1,figsize=(10,8))
    # plt.plot(np.arange(len(result)),y_test,'go-',label='true value')
    # plt.plot(np.arange(len(result)),result,'ro-',label = 'predict value')
    # plt.title('score: %f'%score)
    # plt.legend()
    # plt.show()
    # tl.say("是否保存模型：1 不保存 其他 保存")
    # try:
    #     param=int(raw_input())
    #     if param!=1:
    #         filename='./mos/mos.sav'
    #         tl.saveModel(model,filename)
    #         tl.say("保存模型")
    # except:
    #     tl.say("参数异常，保存模型并退出")
    #     filename='./mos/mos.sav'
    #     tl.saveModel(model,filename)
    
    

def createPic(clf):
    import pydotplus
	# dot_data = tree.export_graphviz(clf, out_file=None) 

    dot_data = tree.export_graphviz(clf, out_file=None,  #指定不同类别颜色
	                         filled=True, rounded=True, 
                             feature_names=names,  
                            #  class_names=className,   
	                         special_characters=True) 
    graph = pydotplus.graph_from_dot_data(dot_data) 
    graph.write_png("./mos/mos.png")

def main():
    url ='G:\\input\\three\\result.txt'  # \\two
    x,y = load_data(url)

    biaozhun=[]
    numsize=500
    var=1
    while var==1:
        tl.say("选择数据处理规则：0、退出 1、标准化 2、正则化 3、归一化 4、不做处理")
        start =time.time()
        try:
            param=int(raw_input())
        except:
            param=1
        if(param ==1):
            for i in range(numsize):
                scaler=tl.zScore(x)
                x=scaler.transform(x)
                biaozhun.append(try_method(x,y))

        elif(param ==2):
            for i in range(numsize):
                scaler=tl.normalization(x)
                x=scaler.transform(x)
                biaozhun.append(try_method(x,y))

        elif (param ==3 ):
            for i in range(numsize):
                x=tl.scale(x)
                biaozhun.append(try_method(x,y))
        elif (param == 4):
            for i in range(numsize):
                biaozhun.append(try_method(x,y))
        elif (param ==0):
            sys.exit()
        data=np.array(biaozhun)
        mean=np.mean(data)
        tl.say("计算"+str(numsize)+"次后MSE平均数为："+str(mean))
        tl.say("运行时间"+str(time.time()-start)+"秒")
        print'\n',



if __name__ == '__main__':
    main()
